package com.ctw.tinyservices.id.server.token.handler;

import com.ctw.tinyservices.id.common.config.DataSourceConfig;
import com.ctw.tinyservices.id.common.entity.IdToken;
import com.ctw.tinyservices.id.common.utils.LogUtils;
import com.ctw.tinyservices.id.server.lifecycle.AbstractIdServerLifecycle;
import com.ctw.tinyservices.id.server.token.dao.impl.IdTokenDAOImpl;
import com.google.common.base.Strings;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author TongWei.Chen 2022/4/2 17:42
 *
 * IdToken 处理器
 **/
@Component
public class IdTokenHandler extends AbstractIdServerLifecycle {
    private static Map<String /* bizType */, Set<String> /* token */> cacheTokenMap = new ConcurrentHashMap<>();

    private ScheduledExecutorService service = null;

    public boolean canVisit(String bizType, String token) {
        if (Strings.isNullOrEmpty(bizType) || Strings.isNullOrEmpty(token)) {
            return false;
        }
        Set<String> tokenSet = cacheTokenMap.get(bizType);
        return (null != tokenSet && tokenSet.contains(token));
    }

    private Map<String, Set<String>> listToMap(List<IdToken> idTokenList) {
        Map<String, Set<String>> map = new HashMap<>(64);
        if (null != idTokenList && idTokenList.size() > 0) {
            for (IdToken token : idTokenList) {
                if (! map.containsKey(token.getBizType())) {
                    map.put(token.getBizType(), new HashSet<>());
                }
                map.get(token.getBizType()).add(token.getToken());
            }
        }
        return map;
    }

    private void updateCacheFromDbAtEveryMinute() {
        service = Executors.newSingleThreadScheduledExecutor(r -> {
            Thread t = new Thread(r);
            t.setName("check-cacheTokenMap-thread");
            t.setDaemon(true);
            return t;
        });
        service.scheduleWithFixedDelay(this::initCacheTokenMap, 60, 60, TimeUnit.SECONDS);
    }

    private void initCacheTokenMap() {
        // Config dataSource
        IdTokenDAOImpl idTokenDAO = new IdTokenDAOImpl(new JdbcTemplate(DataSourceConfig.getInstance().getDruidDataSource()));
        LogUtils.info(IdTokenHandler.class, "SegmentGenerator doInit begin");
        List<IdToken> idTokenList = idTokenDAO.listEnabled();
        cacheTokenMap = listToMap(idTokenList);
        LogUtils.info(IdTokenHandler.class, "SegmentGenerator doInit end,  token size:{}", idTokenList == null ? 0 : idTokenList.size());
    }

    @Override
    protected void doInit() {
        initCacheTokenMap();
    }

    @Override
    protected void doStart() {
        LogUtils.info(IdTokenHandler.class, "SegmentGenerator doStart data begin...");
        // 每分钟刷新cache一次
        updateCacheFromDbAtEveryMinute();
        LogUtils.info(IdTokenHandler.class, "SegmentGenerator doStart data end...");
    }

    @Override
    protected void doStop() {
        LogUtils.info(IdTokenHandler.class, "IdTokenHandler doStop begin...");
        service.shutdownNow();
        LogUtils.info(IdTokenHandler.class, "IdTokenHandler doStop end...");
    }

}
